package com.easemob.easeui.model;

import java.io.File;
import java.io.IOException;
import java.util.Date;

import android.content.Context;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.SystemClock;
import android.text.format.Time;

import com.easemob.EMError;
import com.easemob.chat.EMChatManager;
import com.easemob.util.EMLog;
import com.easemob.util.PathUtil;

public class EaseVoiceRecorder {
	MediaRecorder recorder;

	static final String PREFIX = "voice";
	static final String EXTENSION = ".amr";

	private boolean isRecording = false;
	private long startTime;
	private String voiceFilePath = null;
	private String voiceFileName = null;
	private File file;
	private Handler handler;

	public EaseVoiceRecorder(Handler handler) {
		this.handler = handler;
	}

	/**
	 * start recording to the file
	 */
	public String startRecording(Context appContext) {
		file = null;
		try {
			// need to create recorder every time, otherwise, will got exception
			// from setOutputFile when try to reuse
			if (recorder != null) {
				recorder.release();
				recorder = null;
			}
			recorder = new MediaRecorder();
			recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
			recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
			recorder.setAudioChannels(1); // MONO
			recorder.setAudioSamplingRate(8000); // 8000Hz
			recorder.setAudioEncodingBitRate(64); // seems if change this to
													// 128, still got same file
													// size.
			// one easy way is to use temp file
			// file = File.createTempFile(PREFIX + userId, EXTENSION,
			// User.getVoicePath());
			voiceFileName = getVoiceFileName(EMChatManager.getInstance()
					.getCurrentUser());
			voiceFilePath = PathUtil.getInstance().getVoicePath() + "/"
					+ voiceFileName;
			file = new File(voiceFilePath);
			recorder.setOutputFile(file.getAbsolutePath());
			recorder.prepare();
			isRecording = true;
			recorder.start();
		} catch (IOException e) {
			EMLog.e("voice", "prepare() failed");
		}
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					while (isRecording) {
						android.os.Message msg = new android.os.Message();
						msg.what = recorder.getMaxAmplitude() * 13 / 0x7FFF;
						handler.sendMessage(msg);
						SystemClock.sleep(100);
					}
				} catch (Exception e) {
					// from the crash report website, found one NPE crash from
					// one android 4.0.4 htc phone
					// maybe handler is null for some reason
					EMLog.e("voice", e.toString());
				}
			}
		}).start();
		startTime = new Date().getTime();
		EMLog.d("voice",
				"start voice recording to file:" + file.getAbsolutePath());
		return file == null ? null : file.getAbsolutePath();
	}

	/**
	 * stop the recoding
	 * 
	 * @return seconds of the voice recorded
	 */

	public void discardRecording() {
		if (recorder != null) {
			try {
				recorder.stop();
				recorder.release();
				recorder = null;
				if (file != null && file.exists() && !file.isDirectory()) {
					file.delete();
				}
			} catch (IllegalStateException e) {
			} catch (RuntimeException e) {
			}
			isRecording = false;
		}
	}

	public int stopRecoding() {
		if (recorder != null) {
			isRecording = false;
			recorder.stop();
			recorder.release();
			recorder = null;

			if (file == null || !file.exists() || !file.isFile()) {
				return EMError.INVALID_FILE;
			}
			if (file.length() == 0) {
				file.delete();
				return EMError.INVALID_FILE;
			}
			int seconds = (int) (new Date().getTime() - startTime) / 1000;
			EMLog.d("voice", "voice recording finished. seconds:" + seconds
					+ " file length:" + file.length());
			return seconds;
		}
		return 0;
	}

	protected void finalize() throws Throwable {
		super.finalize();
		if (recorder != null) {
			recorder.release();
		}
	}

	private String getVoiceFileName(String uid) {
		Time now = new Time();
		now.setToNow();
		return uid + now.toString().substring(0, 15) + EXTENSION;
	}

	public boolean isRecording() {
		return isRecording;
	}

	public String getVoiceFilePath() {
		return voiceFilePath;
	}

	public String getVoiceFileName() {
		return voiceFileName;
	}
}
